package com.example.androidexample.qr;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.NotFoundException;
import com.google.zxing.Result;
import com.google.zxing.ResultPoint;
import com.google.zxing.ResultPointCallback;
import com.google.zxing.common.HybridBinarizer;

import java.util.Arrays;
import java.util.Hashtable;
import java.util.Vector;

public abstract class FormatReader {
    private MultiFormatReader reader = new MultiFormatReader();

    private final int MAX_WIDTH = 400;
    private final int MAX_HEIGHT = 400;

    private ResultPointCallback resultPointCallback = new ResultPointCallback() {
        @Override
        public void foundPossibleResultPoint(ResultPoint point) {
            onResultPoint(point);
        }
    };

    protected abstract void onResultPoint(ResultPoint result);

    public FormatReader() {
        Hashtable<DecodeHintType, Object> hints = new Hashtable<>();
        Vector<BarcodeFormat> decodeFormats = new Vector<>();
        decodeFormats.addAll(Arrays.asList(
                BarcodeFormat.UPC_A,
                BarcodeFormat.UPC_E,
                BarcodeFormat.EAN_8,
                BarcodeFormat.EAN_13,
                BarcodeFormat.UPC_EAN_EXTENSION
        ));

        decodeFormats.addAll(Arrays.asList(
                BarcodeFormat.CODE_39,
                BarcodeFormat.CODE_93,
                BarcodeFormat.CODE_128,
                BarcodeFormat.CODABAR,
                BarcodeFormat.ITF
        ));

        decodeFormats.addAll(Arrays.asList(
                BarcodeFormat.QR_CODE,
                BarcodeFormat.DATA_MATRIX,
                BarcodeFormat.AZTEC,
                BarcodeFormat.PDF_417,
                BarcodeFormat.MAXICODE,
                BarcodeFormat.RSS_14,
                BarcodeFormat.RSS_EXPANDED
        ));

        hints.put(DecodeHintType.POSSIBLE_FORMATS,decodeFormats);
        hints.put(DecodeHintType.CHARACTER_SET,"UTF-8");
        hints.put(DecodeHintType.NEED_RESULT_POINT_CALLBACK,resultPointCallback);
        reader.setHints(hints);
    }

    protected DecodeResult decodeIMG(String path) {
        // load bitmap
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;

        BitmapFactory.decodeFile(path, options);

        options.inSampleSize = calculateInSampleSize(options);
        options.inJustDecodeBounds = false;

        Bitmap bmp = BitmapFactory.decodeFile(path, options);
        return decode(new BitmapLuminanceSource(bmp));
    }

    private int calculateInSampleSize(BitmapFactory.Options options) {
        int height = options.outHeight;
        int width = options.outWidth;
        int inSampleSize = 1;
        while (width >= MAX_WIDTH && height >= MAX_HEIGHT) {
            inSampleSize = inSampleSize<<1;
        }
        return inSampleSize;
    }

    protected DecodeResult decode(LuminanceSource source) {
        try {
            Result result = reader.decodeWithState(new BinaryBitmap(new HybridBinarizer(source)));
            return new DecodeResult(true,result.getText());
        } catch (NotFoundException e) {
            e.printStackTrace();
        } finally {
            reader.reset();
        }

        return new DecodeResult(false,"");
    }
}
/*
     * 为耗时方法，应当异步化
         * 相机的 preview 尺寸是x、y颠倒的，在这里需要再转过来
         * 图像信息存储在一维数组里，转换后
        var rotatedData : ByteArray? = null
        //小窗模式变为正常模式时会出现数组越界的异常  暂时无法解决
        try {
        rotatedData = rotateData(frame.data, frame.widthIN, frame.heightIN)
        } catch (exception: ArrayIndexOutOfBoundsException) {
        Log.e(TAG, "ArrayIndexOutOfBoundsException error : $exception")
        return DecodeResult()
        }
        val width = frame.heightIN
        val height = frame.widthIN

        val region = UseCaseCreator.regionUseCase
        val rotatedRect = Rect(region.identificationRect).apply {
        left = left * frame.heightIN / region.screenRect.width()
        right = right * frame.heightIN / region.screenRect.width()
        top = top * frame.widthIN / region.screenRect.height()
        bottom = bottom * frame.widthIN / region.screenRect.height()
        }

        try {
        val source = PlanarYUVLuminanceSource(rotatedData, width, height,
        rotatedRect.left, rotatedRect.top, rotatedRect.width(), rotatedRect.height(),
        false)

        return decode(source)
        } catch (exception: IllegalArgumentException) {
        Log.e(TAG, "PlanarYUVLuminanceSource error : $exception")
        }

        return DecodeResult()
        }
        *
        * private fun rotateData(data: ByteArray, width: Int, height: Int): ByteArray {
            val rotatedData = ByteArray(data.size)
            for (y in 0 until height) {
                for (x in 0 until width) {
                    rotatedData[x * height + height - y - 1] = data[x + y * width]
                }
            }

            return rotatedData
        }
 */